package addition.nio;

import org.junit.Test;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Date;
import java.util.Iterator;

public class NoBlockingNioDemo {

    @Test
    public void server() throws IOException {
        // 1. 获取通道
        ServerSocketChannel ssChannel = ServerSocketChannel.open();

        // 2. 切换为非阻塞式 IO
        ssChannel.configureBlocking(false);

        // 3. 绑定连接
        ssChannel.bind(new InetSocketAddress(8080));

        // 4. 创建选择器
        Selector selector = Selector.open();

        // 5. 将通道注册到选择器上，接听 接收操作
        ssChannel.register(selector, SelectionKey.OP_ACCEPT);

        // 6. 轮询检测接听
        while (selector.select() > 0) {
            // 7. 获取选择键
            Iterator<SelectionKey> it = selector.selectedKeys().iterator();

            // 8. 遍历选择键
            while (it.hasNext()) {
                SelectionKey sk = it.next();

                // 9. 类型判断
                if (sk.isAcceptable()) {  // 接收操作
                    // 10. 获取接收客户端通道
                    SocketChannel sChannel = ssChannel.accept();

                    // 11. 切换为非阻塞式 IO
                    sChannel.configureBlocking(false);

                    // 12. 注册到选择器，监听 读操作
                    sChannel.register(selector, SelectionKey.OP_READ);
                } else if (sk.isReadable()) {  // 读操作
                    // 13. 获取通道
                    SocketChannel sChannel = (SocketChannel) sk.channel();

                    // 14. 分配缓冲区
                    ByteBuffer buf = ByteBuffer.allocate(1024);

                    // 15. 读取内容
                    int len;
                    while ((len = sChannel.read(buf)) != -1) {
                        // 16. 切换为缓冲区为读模式
                        buf.flip();
                        // 17. 读取缓冲区
                        System.out.println(new String(buf.array(), 0, len));
                        // 19. 清空缓冲区
                        buf.clear();
                    }
                }

                // 20. 删除键
                it.remove();
            }
        }

    }

    @Test
    public void client() throws IOException {
        // 1. 获取通道
        SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("localhost", 8080));

        // 2. 将通道切换为非阻塞式 IO
        sChannel.configureBlocking(false);

        // 3. 分配缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);

        // 4. 写入内容
        buf.put(new Date().toString().getBytes());

        // 5. 切换为读模式
        buf.flip();

        // 6. 写入内容
        sChannel.write(buf);
        buf.clear();

        // 7. 关闭通道
        sChannel.close();
    }

}
